﻿using Devonline.Entity;
using Microsoft.Extensions.Logging;

namespace Devonline.Communication.Messages;

/// <summary>
/// 消息通讯器
/// </summary>
/// <typeparam name="TMessage">消息类型</typeparam>
/// <typeparam name="TKey">主键类型</typeparam>
/// <typeparam name="TContent">消息内容类型</typeparam>
public abstract class MessageCommunicator<TMessage, TKey, TContent> :
    SignalCommunicator<TMessage>,
    IMessageCommunicator<TMessage, TKey, TContent>,
    ICommunicator<TMessage>
    where TKey : IConvertible
    where TMessage : class, IMessage<TKey, TContent>, new()
{
    protected const string LOG_SEND_MESSAGE = LOG_SEND_INFO + " to send the message <{message}>";
    protected const string LOG_RECEIVE_MESSAGE = LOG_RECEIVE_INFO + " and received the message <{message}>";

    public MessageCommunicator(ILogger<MessageCommunicator<TMessage, TKey, TContent>> logger, MessageOptions setting) : base(logger, setting) { }

    #region 客户端接收消息的事件处理委托方法
    /// <summary>
    /// 收到已读消息时执行的事件处理委托方法
    /// </summary>
    public event EventHandler<TMessage>? Read;
    /// <summary>
    /// 收到已读消息时执行的事件处理委托方法
    /// </summary>
    public event EventHandler<TMessage>? Ack;
    #endregion

    /// <summary>
    /// 关闭通讯器
    /// </summary>
    public override async Task StopAsync()
    {
        if (_connection == null)
        {
            return;
        }

        _connection.Remove(nameof(Ack));
        _connection.Remove(nameof(Read));
        Monitor -= OnMonitor;
        await base.StopAsync();
    }

    #region 客户端发送消息的方法
    /// <summary>
    /// 默认的发送方法, 发送完整的消息体
    /// </summary>
    /// <param name="message"></param>
    /// <returns></returns>
    public override Task SendAsync(TMessage message)
    {
        message.Sender ??= User.GetValueOrDefault<TKey>();
        if (message.From == null && (!string.IsNullOrWhiteSpace(Client)))
        {
            message.From = Client.To<TKey>();
        }

        LogSendMessage(message);
        return base.SendAsync(message);
    }

    /// <summary>
    /// 仅发送文本消息到默认接收者的方法
    /// </summary>
    /// <param name="content"></param>
    /// <returns></returns>
    public virtual Task SendAsync(TContent content) => SendAsync(SetDefaultReceiver(new TMessage { Content = content }));
    /// <summary>
    /// 仅发送指定类型的消息内容到默认接收者的方法
    /// </summary>
    /// <param name="content"></param>
    /// <param name="type">消息类型</param>
    /// <returns></returns>
    public virtual Task SendAsync(TContent content, MessageType type = MessageType.Text) => SendAsync(SetDefaultReceiver(new TMessage { Content = content, Type = type }));

    /// <summary>
    /// 仅发送文本消息到指定接收者
    /// 消息接收者为指定接收者或所有人
    /// </summary>
    /// <param name="content">消息内容</param>
    /// <param name="receiver">消息接收者, null or empty: 所有人</param>
    /// <returns></returns>
    public virtual Task SendAsync(TContent content, TKey? receiver = default) => SendAsync(new TMessage { Content = content, Receiver = receiver, Type = MessageType.Text });
    /// <summary>
    /// 发送指定类型消息内容发送到指定消息接收者
    /// 消息接收者为指定接收者或所有人
    /// </summary>
    /// <param name="content">消息内容</param>
    /// <param name="receiver">消息接收者, null or empty: 所有人</param>
    /// <param name="type">消息类型</param>
    /// <returns></returns>
    public virtual Task SendAsync(TContent content, TKey? receiver = default, MessageType type = MessageType.Text) => SendAsync(new TMessage { Type = type, Receiver = receiver, Content = content });
    /// <summary>
    /// 缓存更新
    /// 缓存消息接收者为指定接收者或所有人
    /// </summary>
    /// <param name="cache"></param>
    /// <returns></returns>
    public virtual Task RefreshCacheAsync(TContent cache, TKey? receiver = default) => SendAsync(new TMessage { Content = cache, Type = MessageType.Cache, Receiver = receiver });

    /// <summary>
    /// 将通知内容发送到到默认消息接收者或指定消息接收者
    /// </summary>
    /// <param name="content">消息内容</param>
    /// <param name="receiver">消息接收者</param>
    /// <returns></returns>
    public virtual Task NoticeAsync(TContent content, TKey? receiver = default) => SendAsync(SetDefaultReceiver(new TMessage { Content = content, Receiver = receiver, Type = MessageType.Notice }));
    /// <summary>
    /// 将告警内容发送到到默认消息接收者或指定消息接收者
    /// </summary>
    /// <param name="content">消息内容</param>
    /// <param name="receiver">消息接收者</param>
    /// <returns></returns>
    public virtual Task WarningAsync(TContent content, TKey? receiver = default) => SendAsync(SetDefaultReceiver(new TMessage { Content = content, Receiver = receiver, Type = MessageType.Warning }));
    /// <summary>
    /// 将错误内容发送到到默认消息接收者或指定消息接收者
    /// </summary>
    /// <param name="content">消息内容</param>
    /// <param name="receiver">消息接收者</param>
    /// <returns></returns>
    public virtual Task ErrorAsync(TContent content, TKey? receiver = default) => SendAsync(SetDefaultReceiver(new TMessage { Content = content, Receiver = receiver, Type = MessageType.Error }));

    /// <summary>
    /// 执行指令/命令
    /// 指令接收者为指定接收者或默认接收者
    /// </summary>
    /// <param name="type">指令类型</param>
    /// <param name="receiver">指令接收者</param>
    /// <param name="content">指令内容</param>
    /// <returns></returns>
    public virtual Task ExecuteAsync(MessageType type = MessageType.Execute, TKey? receiver = default, TContent? content = default) => SendAsync(SetDefaultReceiver(new TMessage { Type = type, Receiver = receiver, Content = content }));

    /// <summary>
    /// 发送回复消息
    /// 消息接收者为原始消息发送者
    /// </summary>
    /// <param name="content">消息内容</param>
    /// <param name="message">回复的消息</param>
    /// <param name="type">消息类型</param>
    /// <returns></returns>
    public virtual Task ReplyAsync(TContent content, TMessage message, MessageType type = MessageType.Text) => SendAsync(new TMessage { Type = type, Reply = message.Id, Receiver = message.Sender, To = message.From });
    /// <summary>
    /// 发送已读消息
    /// 消息接收者为原始消息发送者
    /// </summary>
    /// <param name="id">消息编号</param>
    /// <returns></returns>
    public virtual Task ReadAsync(TKey id)
    {
        var message = InitMessage(new TMessage { Id = id, Type = MessageType.Read });
        LogSendMessage(message, nameof(Read));
        return base.SendAsync(nameof(Read), message);
    }
    #endregion

    #region 集成或重写的方法, 内部方法
    /// <summary>
    /// 初始化通讯器
    /// </summary>
    protected override void OnInitial()
    {
        base.OnInitial();

        //注册默认收到消息已读的处理方法
        OnRead();
        //注册默认收到消息回执时的处理方法
        OnAck();
        //注册监控事件处理方法
        Monitor += OnMonitor;
    }
    /// <summary>
    /// 接收消息
    /// </summary>
    /// <param name="message"></param>
    protected override void OnReceive(TMessage message)
    {
        LogReceiveMessage(message);
        if (message.Sender?.ToString() != User)
        {
            //客户端只针对非控制类消息发送回执
            new Task(async () => await base.SendAsync(nameof(Ack), InitMessage(new TMessage { Id = message.Id, Type = MessageType.Ack }))).Start();
        }

        base.OnReceive(message);
    }
    /// <summary>
    /// 收到消息已读时执行的委托处理方法
    /// </summary>
    /// <param name="action"></param>
    protected virtual void OnRead() => OnHandler(nameof(Read), message =>
    {
        LogReceiveMessage(message, nameof(Read));
        Read?.Invoke(this, message);
    });
    /// <summary>
    /// 收到消息已收到的回执时执行的委托处理方法
    /// </summary>
    /// <param name="action"></param>
    protected virtual void OnAck() => OnHandler(nameof(Ack), message =>
    {
        LogReceiveMessage(message, nameof(Ack));
        Ack?.Invoke(this, message);
    });

    /// <summary>
    /// 使用当前的默认配置填充消息体缺失部分
    /// </summary>
    /// <param name="message"></param>
    protected virtual TMessage InitMessage(TMessage message)
    {
        if (message.Sender == null && (!string.IsNullOrWhiteSpace(User)))
        {
            message.Sender = User.To<TKey>();
        }

        if (message.Receiver == null && (!string.IsNullOrWhiteSpace(_clientSetting.Receiver)))
        {
            message.Receiver = _clientSetting.Receiver.To<TKey>();
        }

        if (message.From == null && (!string.IsNullOrWhiteSpace(Client)))
        {
            message.From = Client.To<TKey>();
        }

        return message;
    }
    /// <summary>
    /// 设置消息发送到默认接收者
    /// </summary>
    /// <param name="message"></param>
    protected virtual TMessage SetDefaultReceiver(TMessage message)
    {
        if (message.Receiver == null && (!string.IsNullOrWhiteSpace(_clientSetting.Receiver)))
        {
            message.Receiver = _clientSetting.Receiver.To<TKey>();
        }

        return message;
    }
    /// <summary>
    /// 记录发送消息日志
    /// </summary>
    /// <param name="message"></param>
    /// <param name="method"></param>
    protected virtual void LogSendMessage(TMessage message, string method = METHOD_SEND) => _logger.LogDebug(LOG_SEND_MESSAGE, _options, method, message);
    /// <summary>
    /// 记录接收消息日志
    /// </summary>
    /// <param name="message"></param>
    /// <param name="method"></param>
    protected virtual void LogReceiveMessage(TMessage message, string method = nameof(Receive)) => _logger.LogDebug(LOG_RECEIVE_MESSAGE, _options, method, message);
    /// <summary>
    /// 客户端连接监控
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    private async void OnMonitor(object? sender, EventArgs args)
    {
        if (IsConnected)
        {
            var heartbeat = "Heartbeat";
            _logger.LogInformation(LOG_SEND_INFO, _options, heartbeat);
            await base.SendAsync(heartbeat);
        }
    }
    #endregion
}

/// <summary>
/// 默认的文本消息通讯器
/// </summary>
public class MessageCommunicator : MessageCommunicator<Message, string, string>, IMessageCommunicator
{
    public MessageCommunicator(ILogger<MessageCommunicator> logger, MessageOptions setting) : base(logger, setting) { }
}